Introduction
The very popular R package ggplot2
is based on a system called the Grammar
of Graphics by Leland Wilkinson which aims to create a grammatical
rules for the development of graphics. It is part of a larger group of
packages called “the tidyverse.”
What is the tidyverse?
The package ggplot2 is a part of a larger collection of
packages called “the tidyverse”
that are designed for data science. You can certainly use R without
using the tidyverse, but it has many packages that I think will make
your life a lot easier.
We can install just ggplot2 or install all of the
packages in the core tidyverse (which is what I’d recommend since we
will use the others too), which include:
dplyr: for
data manipulation
ggplot2: a
“grammar of graphics” for creating beautiful plots
readr: for
reading in rectangular data (i.e., Excel-style formatting)
tibble:
using tibbles as modern/better dataframes
stringr:
handling strings (i.e., text or stuff in quotes)
forcats:
for handling categorical variables (i.e., factors) (meow!)
tidyr: to
make “tidy data”
purrr: for
enhancing functional programming (also meow!)
We will be using many of these other packages in this course, but
will talk about them as we go. There are more tidyverse packages outside
of these core eight, and we will talk about some of them another
time.
tl;dr Tidyverse has a lot of packages that make data
analysis easier. None of them are required, but I think you’ll find many
tidyverse approaches easier and more intuitive than using base R.
You can find here
some examples of comparing tidyverse and base R syntax.
Installing ggplot & tidyverse
To install packages in R that are on the Comprehensive R Archive Network
(CRAN), you can use the function
install.packages().
install.packages("tidyverse")
install.packages("ggplot2")
We only need to install packages once. But, every time we want to use
them, we need to “load” them, and can do this using the function
library().
tl:dr install.packages() once,
library() every time.
A plotting framework
You can think about a ggplot as being composed of layers. You start
with your data, and continue to add layers until you get the plot that
you want. This might sound a bit abstract so I am going to talk through
this with an example.
The data will be using was collected by Dr. Lisa Lendway from her
home garden in 2020, and can be within her R package gardenR. She
has collected information from June through October about how much of
each garden crop she harvested each day. Since this is a Horticulture
and Crop Science course, and I like gardening (and R), I thought we’d
use it to learn about ggplot2.
We have previously used
install.packages("name_of_package") to download packages,
but this function only works for packages that are on the Comprehensive
R Archive Network CRAN.
Dr. Lendway’s package isn’t on CRAN, so we will use the helper package
devtools to help us download it. The double colon
:: syntax allows you to access a function from a particular
package. In this case, we are using the package devtools
and the function install_github() to download
gardenR from Dr. Lendway’s github.
# tidyverse all day every day
library(tidyverse)
# if you don't have "devtools" and "gardenR", uncomment the lines below
# install.packages("devtools")
# devtools::install_github("llendway/gardenR")
# load the package "gardenR"
library(gardenR)
What is in this garden_harvest dataset?
glimpse(garden_harvest)
## Rows: 781
## Columns: 5
## $ vegetable <chr> "lettuce", "radish", "lettuce", "lettuce", "radish", "lettuc…
## $ variety <chr> "reseed", "Garden Party Mix", "reseed", "reseed", "Garden Pa…
## $ date <date> 2020-06-06, 2020-06-06, 2020-06-08, 2020-06-09, 2020-06-11,…
## $ weight <dbl> 20, 36, 15, 10, 67, 12, 9, 8, 53, 19, 14, 10, 48, 58, 8, 121…
## $ units <chr> "grams", "grams", "grams", "grams", "grams", "grams", "grams…
range(garden_harvest$date)
## [1] "2020-06-06" "2020-10-18"
I am going to generate a quick plot to use to make the description of
the parts of a plot a little bit more tangible. It’s totally ok if you
don’t understand this code. Once we describe the parts, we are going to
go through each one individually and see how each bit contributes
towards the plot below.
# filter data to include only tomatoes
# filter() is a useful function from dplyr (part of tidyverse)
# it allows us to select observations based on their values
garden_harvest_tomato <- garden_harvest %>%
filter(vegetable == "tomatoes")
# plot
ggplot(data = garden_harvest_tomato, aes(x = date, y = weight, color = variety)) +
geom_line() +
geom_point(size = 1) +
facet_wrap(vars(variety)) +
scale_color_viridis_d() +
coord_cartesian() +
theme_classic() +
theme(legend.position = "none") +
labs(x = "Month, in 2020",
y = "Weight (g)",
title = "Total harvest weight of tomatoes by day in summer 2020",
subtitle = "Collected by Dr. Lisa Lendway (and from the package gardenR)")

The general parts in a ggplot object are:
- data: the dataframe you want to plot (here, we are filtering
garden_harvest to only include the data for tomatoes)
- aesthetic
mappings: which describe how the variables in your data are mapped
to the visual ‘aesthetics’ you see in your plot (here, mapping date to
the x-axis, weight to the y-axis, and color to variety)
- geometries
or “geoms”: tell R what type of plot you want to make, typically
start
geom_ (here, geom_line() to make a line
plot, and reminder, you don’t need to pick just one!)
- scales:
control how the variables are related to the visual properties (here, we
are using
scale_color_discrete_d() to set the colors for
the plot)
- facets:
generates small multiples of plots allowing easy visual comparison
(here, making small line plots for each variety using
facet_wrap())
- coordinates:
controls how x and y are visualized in your plot (here, using
coord_cartesian() which is actually the default, which just
plots as Cartesian coordinates)
- labels:
adjusting how the labels of the plots look (here, labeling the x and y
axis, providing a title and a subtitle)
- theme:
controlling the non-data parts of your plots (here, using both
theme_minimal() which provides an overall theme, and using
theme() to remove the legend which we don’t need because we
have facets)
Syntax
Let’s go through the syntax in more detail now. I am going to
introduce all the syntax, then we will focus this week through geoms,
and do the rest next week. I want to give you an overview of what you
can do with ggplot, then we will get into more detail.
Data
The first argument passed to your plot is the data. How did I know
that? It’s in the documentation.
?ggplot()
The simplest ggplot code you can write, just using the
ggplot() function and indicating the data we want to use.
Because data is the default first argument, you can actually omit the
data = part of this code and it will work just the
same.
ggplot(data = garden_harvest)

Why do we not see a plot? Well we haven’t told R what to plot! We are
getting the first “base” layer of the plot.
For those of you who are familiar with the tidyverse pipe
%>%, you can also pipe the data to the ggplot function.
When reading code, you can interpret the pipe as “and then.” Here, take
the garden_harvest data, and then, run
ggplot(). Writing code in this way is my preference so I
tend to code like this.
garden_harvest %>%
ggplot()

Still nothing. Well that’s what we would expect.
Aesthetic mappings aes()
Now that we’ve indicated our data, we can add aesthetics mapping so
we can work towards actually see a plot. We want to make a line plot
where on the x-axis we have the date (date), and on the
y-axis we have how much tomato was harvested (weight).
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight))

So we have progressed from a blank plot, but we still do not have a
plot by basically anyone’s defintion. Why not?
Even though we have indicated to R our data and aesthetic mappings,
we have not indicated what precisely to do with our data. We have said
what we want on x and y (and now we can see those labelled appearing)
but we have not indicated what type of plot we want. And, we
can do that in the next step, by adding a geom_.
Geoms geom_
Now let’s indicate what type of plot we want. In this example, we are
going to make a line plot, and to do that we will use geom_line()
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight)) +
geom_line()

We have a plot! It’s not a really good plot, but its a plot and we
can work from here.
You can see that what R has done is take each date, and plotted the
total weight of tomatoes harvested on that day. What we can see from
this part is that in the beginning of the season, there is little tomato
production (this is not surprising to anyone who knows about
horticulture or has grown tomatoes before), and production increases as
the season progresses. We don’t see any harvest after mid-October which
makes sense because Dr. Lendway lives in Minnesota and probably there
was a frost that killed the plants (hence no more 🍅).
A note about aesthetic mappings now that we have introduced geoms
-aes() can go in two places:
- in the
ggplot() call, and this means they will inherit
for every layer of the plot
- in a specific
geom_, and those aesthetics will only be
for that specific geom.
So we can make the same plot we saw above by mapping aesthetics
within geom_line().
garden_harvest_tomato %>%
ggplot() +
geom_line(aes(x = date, y = weight))

Let’s say we wanted to see how the harvest of different varieties
looks over the summer? We can take the variable variety and
map it to the aesthetic color.
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight, color = variety)) +
geom_line()

This is till not a beautiful plot, but you are able to see now how
you can map a variable of the data (here, variety) to an
aesthetic (color).
Another important thing to notice here is that now the data is
grouped by variety. We are seeing 12 lines instead of 1. This happens
automatically under the hood. This ‘grouping’ will be maintained across
additional geoms because it is in the global aesthetic mappings for the
plot.
We can also add more than one geom. Let’s try adding
geom_point() so we can better see exactly which times were
sampled in this dataset.
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight, color = variety)) +
geom_line() +
geom_point()

To more fully make the point about global vs aesthetic mappings,
let’s look at an example.
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight)) +
geom_line(aes(color = variety)) +
geom_point()

Here, we can see that how the line layer is being grouped by variety,
while the points are not. This is because the aesthetic mappings for one
geom don’t inherit to the next one. If we want to also color points by
variety, we need to either 1) set this as the global aesthetic mapping
or 2) also set aes(color = variety) in
geom_point() too.
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight)) +
geom_line(aes(color = variety)) +
geom_point(aes(color = variety))

Mapping vs. ‘setting’
If you want to map a variable to an aesthetic, it MUST be within the
aes() statement. If you just want to change the color to
“blue” for example, it should be outside the aes()
statement. Look at the difference.
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight)) +
geom_line(color = "blue")

tl:dr if mapping a variable to an aesthetic, inside
aes(), if not, then outside.
More about aesthetics
It’s hard to talk about how to map to aesthetics before you add a
geom, which is why this content is in this section.
So far we have talked about mapping aesthetics to x,
y, and color. Below is a list of
other aesthetics you can map to:
color (or colour if that suits you better)
and fill
In general color controls the outside/line, and fill controls the
inside of a shape. Some geoms will work only with color or
fill, and work with both. There are a millions ways to
control the color, including by using the R
color names (don’t forget to put them in quotes), or hex codes
(e.g., “FF0000” for red). There are a ton of different color palettes in
R like color
brewer and I’d recommend you to think about using colors that are
color blind friendly like viridis.
Picking a color palette allows continuity across your
presentation/manuscript, and can help in the interpretation of your data
(e.g., having a divergent scale where darker means more abundant, or
pairing colors like light and medium blue to indicate which samples have
some kind of relationship).
linetype
You can change the style of a line based on a variable
garden_harvest_tomato %>%
ggplot(aes(x = date, y = weight)) +
geom_line(aes(linetype = variety))

Wow this is a disaster but you can see the point about mapping
variables to linetype.
Here are some different linetypes you can select from:
size
You can also map variables to size. This could be useful
if you wanted to say make your points bigger when a fold change is
bigger, or bigger when a value is more significant. Below is an example
of mapping weight to size in our example dataset.
garden_harvest_tomato %>%
filter(variety %in% c("Mortgage Lifter", "Brandywine")) %>%
ggplot(aes(x = variety, y = date, size = weight)) +
geom_point()

shape
You can also map variables to shape. This could be useful if you want
points of one treatment on a scatterplot to be circles, a second
treatment triangles, etc. You can combine mapping to shape and color
together which is good for those who are concerned about black and white
printability, but also easy differentiability when viewed on a
computer.
Shapes 0-20 accept only a color aesthetics. Shapes 21-25
accept both a color and fill aesthetic, where
color controls the color of the outside of the shape, and
fill controls the color of the inside of the shape. I
basically always use shapes 21-25.
alpha
Setting alpha allows you to map a variable to the
transparency of a part of your plot. So for example, if you had a
correlation plot, you could make a strong correlation really dark, while
a weak relationship lighter. Alpha can range between 0 and 1, where 0 is
totally transparent, and 1 is completely opaque.
Scales scale_
Using scales allows you to control how the data are linked to the
visual properties of your plot.
Scales allow you to pick colors, shapes, alphas, lines,
transformations (e.g. scaling your axes to a log scale), and others. You
can also use scales to set the limits of your plots.
Facets facet_wrap() and facet_grid()
Faceting allows you to look at your plots using small multiples, to
compare plots that might be otherwise crowded or hard to interpret.
Faceting can be done using facet_wrap() or
facet_grid().
Coordinates coord_
Often the coordinate system used for your plot will be a simple
Cartesian system using x and y. But sometimes, like for making maps or
other specialized plots, you will want to change how x and y map to your
coordinate system.
Labels labs()
Having good labels helps your reader (and you, when you come back to
the plot in the future) understand what its all about.
In the labs() function, you can indicate:
x for the x-axis label
y for the y-axis label
title for a title
subtitle for a subtitle underneath your title
caption for a caption
In theme() you can change characteristics of these
labels like their size, fonts, justfication, etc.
Themes theme() and theme_
Themes will control all the non-data parts of your plot. There are
some pre-set “complete” themes that you can recognize as they’ll be
called theme_XXX(), and you can adjust any theme parameters
by setting parameters within theme(). There are probably 50
parameters you can set within theme() and they include text
size, axis label orientation, the presence of a legend, and many
others.
LS0tCnRpdGxlOiAiZ2dwbG90IDEwMSAoYW5kIPCfjYUpIgphdXRob3I6ICJKZXNzaWNhIENvb3BlcnN0b25lIgpkYXRlOiAiV2VlayA1IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKYGBge3IgZGF0YSBtYXN0ZXJwaWVjZSwgZmlnLmFsdCA9ICJBIGZ1enp5IG1vbnN0ZXIgaW4gYSBiZXJldCBhbmQgc2NhcmYsIGNyaXRpcXVpbmcgdGhlaXIgb3duIGNvbHVtbiBncmFwaCBvbiBhIGNhbnZhcyBpbiBmcm9udCBvZiB0aGVtIHdoaWxlIG90aGVyIGFzc2lzdGFudCBtb25zdGVycyAoYWxzbyBpbiBiZXJldHMpIGNhcnJ5IG92ZXIgYm94ZXMgZnVsbCBvZiBlbGVtZW50cyB0aGF0IGNhbiBiZSB1c2VkIHRvIGN1c3RvbWl6ZSBhIGdyYXBoIChsaWtlIHRoZW1lcyBhbmQgZ2VvbWV0cmljIHNoYXBlcykuIEluIHRoZSBiYWNrZ3JvdW5kIGlzIGEgd2FsbCB3aXRoIGZyYW1lZCBkYXRhIHZpc3VhbGl6YXRpb25zLiBTdHlsaXplZCB0ZXh0IHJlYWRzIOKAnGdncGxvdDI6IGJ1aWxkIGEgZGF0YSBtYXN0ZXJwaWVjZS4iLCBmaWcuY2FwPSAiRmlndXJlIGZyb20gW0FsbGlzb24gSG9yc3RdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3Qvc3RhdHMtaWxsdXN0cmF0aW9ucykiLCBvdXQud2lkdGggPSAiNzAlIiwgZmlnLmFsaWduID0gImNlbnRlciIsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9nZ3Bsb3QyX21hc3RlcnBpZWNlLnBuZyIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoZSB2ZXJ5IHBvcHVsYXIgUiBwYWNrYWdlIFtgZ2dwbG90MmBdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL2luZGV4Lmh0bWwpIGlzIGJhc2VkIG9uIGEgc3lzdGVtIGNhbGxlZCB0aGUgW0dyYW1tYXIgb2YgR3JhcGhpY3NdKGh0dHBzOi8vd3d3LmFtYXpvbi5jb20vR3JhbW1hci1HcmFwaGljcy1TdGF0aXN0aWNzLUNvbXB1dGluZy9kcC8wMzg3MjQ1NDQ4L3JlZj1hc19saV9zc190bCkgYnkgTGVsYW5kIFdpbGtpbnNvbiB3aGljaCBhaW1zIHRvIGNyZWF0ZSBhIGdyYW1tYXRpY2FsIHJ1bGVzIGZvciB0aGUgZGV2ZWxvcG1lbnQgb2YgZ3JhcGhpY3MuIEl0IGlzIHBhcnQgb2YgYSBsYXJnZXIgZ3JvdXAgb2YgcGFja2FnZXMgY2FsbGVkICJ0aGUgdGlkeXZlcnNlLiIKCiMjIFdoYXQgaXMgdGhlIHRpZHl2ZXJzZT8KClRoZSBwYWNrYWdlIGBnZ3Bsb3QyYCBpcyBhIHBhcnQgb2YgYSBsYXJnZXIgY29sbGVjdGlvbiBvZiBwYWNrYWdlcyBjYWxsZWQgWyJ0aGUgdGlkeXZlcnNlIl0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pIHRoYXQgYXJlIGRlc2lnbmVkIGZvciBkYXRhIHNjaWVuY2UuIFlvdSBjYW4gY2VydGFpbmx5IHVzZSBSIHdpdGhvdXQgdXNpbmcgdGhlIHRpZHl2ZXJzZSwgYnV0IGl0IGhhcyBtYW55IHBhY2thZ2VzIHRoYXQgSSB0aGluayB3aWxsIG1ha2UgeW91ciBsaWZlIGEgbG90IGVhc2llci4gCgpXZSBjYW4gaW5zdGFsbCBqdXN0IGBnZ3Bsb3QyYCBvciBpbnN0YWxsIGFsbCBvZiB0aGUgcGFja2FnZXMgaW4gdGhlIGNvcmUgdGlkeXZlcnNlICh3aGljaCBpcyB3aGF0IEknZCByZWNvbW1lbmQgc2luY2Ugd2Ugd2lsbCB1c2UgdGhlIG90aGVycyB0b28pLCB3aGljaCBpbmNsdWRlOgoKLSBbYGRwbHlyYF0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnLyk6IGZvciBkYXRhIG1hbmlwdWxhdGlvbgotIFtgZ2dwbG90MmBdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyk6IGEgImdyYW1tYXIgb2YgZ3JhcGhpY3MiIGZvciBjcmVhdGluZyBiZWF1dGlmdWwgcGxvdHMKLSBbYHJlYWRyYF0oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLyk6IGZvciByZWFkaW5nIGluIHJlY3Rhbmd1bGFyIGRhdGEgKGkuZS4sIEV4Y2VsLXN0eWxlIGZvcm1hdHRpbmcpCi0gW2B0aWJibGVgXShodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnLyk6IHVzaW5nIHRpYmJsZXMgYXMgbW9kZXJuL2JldHRlciBkYXRhZnJhbWVzCi0gW2BzdHJpbmdyYF0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKTogaGFuZGxpbmcgc3RyaW5ncyAoaS5lLiwgdGV4dCBvciBzdHVmZiBpbiBxdW90ZXMpCi0gW2Bmb3JjYXRzYF0oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcvKTogZm9yIGhhbmRsaW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyAoaS5lLiwgZmFjdG9ycykgKG1lb3chKQotIFtgdGlkeXJgXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKTogdG8gbWFrZSAidGlkeSBkYXRhIgotIFtgcHVycnJgXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKTogZm9yIGVuaGFuY2luZyBmdW5jdGlvbmFsIHByb2dyYW1taW5nIChhbHNvIG1lb3chKQoKV2Ugd2lsbCBiZSB1c2luZyBtYW55IG9mIHRoZXNlIG90aGVyIHBhY2thZ2VzIGluIHRoaXMgY291cnNlLCBidXQgd2lsbCB0YWxrIGFib3V0IHRoZW0gYXMgd2UgZ28uIFRoZXJlIGFyZSBtb3JlIHRpZHl2ZXJzZSBwYWNrYWdlcyBvdXRzaWRlIG9mIHRoZXNlIGNvcmUgZWlnaHQsIGFuZCB3ZSB3aWxsIHRhbGsgYWJvdXQgc29tZSBvZiB0aGVtIGFub3RoZXIgdGltZS4KCj4gKip0bDtkcioqIFRpZHl2ZXJzZSBoYXMgYSBsb3Qgb2YgcGFja2FnZXMgdGhhdCBtYWtlIGRhdGEgYW5hbHlzaXMgZWFzaWVyLiAgTm9uZSBvZiB0aGVtIGFyZSByZXF1aXJlZCwgYnV0IEkgdGhpbmsgeW91J2xsIGZpbmQgbWFueSB0aWR5dmVyc2UgYXBwcm9hY2hlcyAgZWFzaWVyIGFuZCBtb3JlIGludHVpdGl2ZSB0aGFuIHVzaW5nIGJhc2UgUi4gIAoKWW91IGNhbiBmaW5kIFtoZXJlXShodHRwczovL3RhdmFyZXNodWdvLmdpdGh1Yi5pby9kYXRhX2NhcnBlbnRyeV9leHRyYXMvYmFzZS1yX3RpZHl2ZXJzZV9lcXVpdmFsZW50cy9iYXNlLXJfdGlkeXZlcnNlX2VxdWl2YWxlbnRzLmh0bWwpIHNvbWUgZXhhbXBsZXMgb2YgY29tcGFyaW5nIHRpZHl2ZXJzZSBhbmQgYmFzZSBSIHN5bnRheC4KCiMjIEluc3RhbGxpbmcgZ2dwbG90ICYgdGlkeXZlcnNlIAoKVG8gaW5zdGFsbCBwYWNrYWdlcyBpbiBSIHRoYXQgYXJlIG9uIHRoZSBbQ29tcHJlaGVuc2l2ZSBSIEFyY2hpdmUgTmV0d29yayAoQ1JBTildKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnLyksIHlvdSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgaW5zdGFsbC5wYWNrYWdlcygpYC4KCmBgYHtyIGluc3RhbGwsIGV2YWwgPSBGQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikKaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmBgYAoKV2Ugb25seSBuZWVkIHRvIGluc3RhbGwgcGFja2FnZXMgb25jZS4gQnV0LCBldmVyeSB0aW1lIHdlIHdhbnQgdG8gdXNlIHRoZW0sIHdlIG5lZWQgdG8gImxvYWQiIHRoZW0sIGFuZCBjYW4gZG8gdGhpcyB1c2luZyB0aGUgZnVuY3Rpb24gYGxpYnJhcnkoKWAuCgo+ICoqdGw6ZHIqKiBgaW5zdGFsbC5wYWNrYWdlcygpYCBvbmNlLCBgbGlicmFyeSgpYCBldmVyeSB0aW1lLgoKIyBnZ3Bsb3QKClRoZSAiZ2ciIGluIGdncGxvdCBzdGFuZHMgZm9yICJncmFtbWFyIG9mIGdyYXBoaWNzIiBhbmQgYWxsIHBsb3RzIHNoYXJlIGEgY29tbW9uIHRlbXBsYXRlLiBUaGlzIGlzIGZ1bmRhbWVudGFsbHkgZGlmZmVyZW50IHRoYW4gcGxvdHRpbmcgdXNpbmcgYSBwcm9ncmFtIGxpa2UgRXhjZWwsIHdoZXJlIHlvdSBmaXJzdCBwaWNrIHlvdXIgcGxvdCB0eXBlLCBhbmQgdGhlbiB5b3UgYWRkIHlvdXIgZGF0YS4gV2l0aCBnZ3Bsb3QsIHlvdSBzdGFydCB3aXRoIGRhdGEsIGFkZCBhIGNvb3JkaW5hdGUgc3lzdGVtLCBhbmQgdGhlbiBhZGQgImdlb21zLCIgd2hpY2ggaW5kaWNhdGUgd2hhdCB0eXBlIG9mIHBsb3QgeW91IHdhbnQuIEEgY29vbCB0aGluZyBhYm91dCBnZ3Bsb3QgaXMgdGhhdCB5b3UgY2FuIGFkZCBhbmQgbGF5ZXIgZGlmZmVyZW50IGdlb21zIHRvZ2V0aGVyLCB0byBjcmVhdGUgYSBmdWxseSBjdXN0b21pemVkIHBsb3QgdGhhdCBpcyBleGFjdGx5IHdoYXQgeW91IHdhbnQuIElmIHRoaXMgc291bmRzIG5lYnVsb3VzIHJpZ2h0IG5vdywgdGhhdCdzIG9rYXksIHdlIGFyZSBnb2luZyB0byB0YWxrIG1vcmUgYWJvdXQgdGhpcy4KCgpgYGB7ciBkYXRhIGV4cGxvcmF0aW9uLCBmaWcuYWx0ID0gIkEgZ3JvdXAgb2YgZnV6enkgcm91bmQgbW9uc3RlcnMgd2l0aCBiaW5vY3VsYXJzLCBiYWNrcGFja3MgYW5kIGd1aWRlIGJvb2tzIGxvb2tpbmcgdXAgYSBncmFwaHMgZmx5aW5nIGFyb3VuZCB3aXRoIHdpbmdzIChsaWtlIGJpcmRlcnMsIGJ1dCB3aXRoIGV4cGxvcmF0b3J5IGRhdGEgdmlzdWFsaXphdGlvbnMpLiBTdHlsaXplZCB0ZXh0IHJlYWRzIOKAnGdncGxvdDI6IHZpc3VhbCBkYXRhIGV4cGxvcmF0aW9uLuKAnSIsIGZpZy5jYXA9ICJGaWd1cmUgZnJvbSBbQWxsaXNvbiBIb3JzdF0oaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9zdGF0cy1pbGx1c3RyYXRpb25zKSIsIG91dC53aWR0aCA9ICI3MCUiLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1nL2dncGxvdDJfZXhwbG9yYXRvcnkucG5nIikKYGBgCgojIFdoYXQgY2FuIHlvdSBkbyB3aXRoIGdncGxvdD8KCiMgQSBwbG90dGluZyBmcmFtZXdvcmsKYGBge3IgbGF5ZXJzLCBmaWcuYWx0ID0gIkEgcGljdG9yaWFsIGRlcGljdGlvbiBvZiB0aGUgZGlmZmVyZW50IGdncGxvdCBsYXllcnMsIHN0YXJ0aW5nIHdpdGggZGF0YSwgYWVzdGhldGljcywgZ2VvbWV0cmllcywgc2NhbGVzLCBmYWNldHMsIGNvb3JkaW5hdGVzLCBsYWJlbHMsIGFuZCB0aGVtZXMiLCBmaWcuY2FwPSAiRmlndXJlIGZyb20gW0FuZHJldyBIZWlzc10oaHR0cHM6Ly9kYXRhdml6czIxLmNsYXNzZXMuYW5kcmV3aGVpc3MuY29tLykiLCBvdXQud2lkdGggPSAiNzAlIiwgZmlnLmFsaWduID0gImNlbnRlciIsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9wbG90dGluZ19mcmFtZXdvcmsucG5nIikKYGBgCgpZb3UgY2FuIHRoaW5rIGFib3V0IGEgZ2dwbG90IGFzIGJlaW5nIGNvbXBvc2VkIG9mIGxheWVycy4gWW91IHN0YXJ0IHdpdGggeW91ciBkYXRhLCBhbmQgY29udGludWUgdG8gYWRkIGxheWVycyB1bnRpbCB5b3UgZ2V0IHRoZSBwbG90IHRoYXQgeW91IHdhbnQuIFRoaXMgbWlnaHQgc291bmQgYSBiaXQgYWJzdHJhY3Qgc28gSSBhbSBnb2luZyB0byB0YWxrIHRocm91Z2ggdGhpcyB3aXRoIGFuIGV4YW1wbGUuCgpUaGUgZGF0YSB3aWxsIGJlIHVzaW5nIHdhcyBjb2xsZWN0ZWQgYnkgW0RyLiBMaXNhIExlbmR3YXldKGh0dHBzOi8vbGlzYWxlbmR3YXkubmV0bGlmeS5hcHAvKSBmcm9tIGhlciBob21lIGdhcmRlbiBpbiAyMDIwLCBhbmQgY2FuIGJlIHdpdGhpbiBoZXIgUiBwYWNrYWdlIFtgZ2FyZGVuUmBdKGh0dHBzOi8vZ2l0aHViLmNvbS9sbGVuZHdheS9nYXJkZW5SKS4gU2hlIGhhcyBjb2xsZWN0ZWQgaW5mb3JtYXRpb24gZnJvbSBKdW5lIHRocm91Z2ggT2N0b2JlciBhYm91dCBob3cgbXVjaCBvZiBlYWNoIGdhcmRlbiBjcm9wIHNoZSBoYXJ2ZXN0ZWQgZWFjaCBkYXkuIFNpbmNlIHRoaXMgaXMgYSBIb3J0aWN1bHR1cmUgYW5kIENyb3AgU2NpZW5jZSBjb3Vyc2UsIGFuZCBJIGxpa2UgZ2FyZGVuaW5nIChhbmQgUiksIEkgdGhvdWdodCB3ZSdkIHVzZSBpdCB0byBsZWFybiBhYm91dCBgZ2dwbG90MmAuCgpXZSBoYXZlIHByZXZpb3VzbHkgdXNlZCBgaW5zdGFsbC5wYWNrYWdlcygibmFtZV9vZl9wYWNrYWdlIilgIHRvIGRvd25sb2FkIHBhY2thZ2VzLCBidXQgdGhpcyBmdW5jdGlvbiBvbmx5IHdvcmtzIGZvciBwYWNrYWdlcyB0aGF0IGFyZSBvbiB0aGUgQ29tcHJlaGVuc2l2ZSBSIEFyY2hpdmUgTmV0d29yayBbQ1JBTl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvKS4gRHIuIExlbmR3YXkncyBwYWNrYWdlIGlzbid0IG9uIENSQU4sIHNvIHdlIHdpbGwgdXNlIHRoZSBoZWxwZXIgcGFja2FnZSBgZGV2dG9vbHNgIHRvIGhlbHAgdXMgZG93bmxvYWQgaXQuIFRoZSBkb3VibGUgY29sb24gYDo6YCBzeW50YXggYWxsb3dzIHlvdSB0byBhY2Nlc3MgYSBmdW5jdGlvbiBmcm9tIGEgcGFydGljdWxhciBwYWNrYWdlLiBJbiB0aGlzIGNhc2UsIHdlIGFyZSB1c2luZyB0aGUgcGFja2FnZSBgZGV2dG9vbHNgIGFuZCB0aGUgZnVuY3Rpb24gYGluc3RhbGxfZ2l0aHViKClgIHRvIGRvd25sb2FkIGBnYXJkZW5SYCBmcm9tIERyLiBMZW5kd2F5J3MgZ2l0aHViLgpgYGB7ciBsaWJyYXJpZXMsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQojIHRpZHl2ZXJzZSBhbGwgZGF5IGV2ZXJ5IGRheQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCiMgaWYgeW91IGRvbid0IGhhdmUgImRldnRvb2xzIiBhbmQgImdhcmRlblIiLCB1bmNvbW1lbnQgdGhlIGxpbmVzIGJlbG93CiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibGxlbmR3YXkvZ2FyZGVuUiIpIAogCiMgbG9hZCB0aGUgcGFja2FnZSAiZ2FyZGVuUiIKbGlicmFyeShnYXJkZW5SKQpgYGAKCldoYXQgaXMgaW4gdGhpcyBgZ2FyZGVuX2hhcnZlc3RgIGRhdGFzZXQ/CmBgYHtyIGludmVzdGlnYXRpbmcgZ2FyZGVuIGhhcnZlc3R9CmdsaW1wc2UoZ2FyZGVuX2hhcnZlc3QpCnJhbmdlKGdhcmRlbl9oYXJ2ZXN0JGRhdGUpCmBgYAoKSSBhbSBnb2luZyB0byBnZW5lcmF0ZSBhIHF1aWNrIHBsb3QgdG8gdXNlIHRvIG1ha2UgdGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBwYXJ0cyBvZiBhIHBsb3QgYSBsaXR0bGUgYml0IG1vcmUgdGFuZ2libGUuIEl0J3MgdG90YWxseSBvayBpZiB5b3UgZG9uJ3QgdW5kZXJzdGFuZCB0aGlzIGNvZGUuIE9uY2Ugd2UgZGVzY3JpYmUgdGhlIHBhcnRzLCB3ZSBhcmUgZ29pbmcgdG8gZ28gdGhyb3VnaCBlYWNoIG9uZSBpbmRpdmlkdWFsbHkgYW5kIHNlZSBob3cgZWFjaCBiaXQgY29udHJpYnV0ZXMgdG93YXJkcyB0aGUgcGxvdCBiZWxvdy4KYGBge3IgZmlsdGVyIHRvbWF0b2VzOyBmaXJzdCBwbG90fQojIGZpbHRlciBkYXRhIHRvIGluY2x1ZGUgb25seSB0b21hdG9lcyAKIyBmaWx0ZXIoKSBpcyBhIHVzZWZ1bCBmdW5jdGlvbiBmcm9tIGRwbHlyIChwYXJ0IG9mIHRpZHl2ZXJzZSkKIyBpdCBhbGxvd3MgdXMgdG8gc2VsZWN0IG9ic2VydmF0aW9ucyBiYXNlZCBvbiB0aGVpciB2YWx1ZXMKZ2FyZGVuX2hhcnZlc3RfdG9tYXRvIDwtIGdhcmRlbl9oYXJ2ZXN0ICU+JQogIGZpbHRlcih2ZWdldGFibGUgPT0gInRvbWF0b2VzIikKCiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGdhcmRlbl9oYXJ2ZXN0X3RvbWF0bywgYWVzKHggPSBkYXRlLCB5ID0gd2VpZ2h0LCBjb2xvciA9IHZhcmlldHkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDEpICsKICBmYWNldF93cmFwKHZhcnModmFyaWV0eSkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArCiAgY29vcmRfY2FydGVzaWFuKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh4ID0gIk1vbnRoLCBpbiAyMDIwIiwKICAgICAgIHkgPSAiV2VpZ2h0IChnKSIsCiAgICAgICB0aXRsZSA9ICJUb3RhbCBoYXJ2ZXN0IHdlaWdodCBvZiB0b21hdG9lcyBieSBkYXkgaW4gc3VtbWVyIDIwMjAiLAogICAgICAgc3VidGl0bGUgPSAiQ29sbGVjdGVkIGJ5IERyLiBMaXNhIExlbmR3YXkgKGFuZCBmcm9tIHRoZSBwYWNrYWdlIGdhcmRlblIpIikKICAKYGBgCgoKVGhlIGdlbmVyYWwgcGFydHMgaW4gYSBnZ3Bsb3Qgb2JqZWN0IGFyZToKCiogZGF0YTogdGhlIGRhdGFmcmFtZSB5b3Ugd2FudCB0byBwbG90IChoZXJlLCB3ZSBhcmUgZmlsdGVyaW5nIGBnYXJkZW5faGFydmVzdGAgdG8gb25seSBpbmNsdWRlIHRoZSBkYXRhIGZvciB0b21hdG9lcykKKiBbYWVzdGhldGljIG1hcHBpbmdzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvYWVzLmh0bWwpOiB3aGljaCBkZXNjcmliZSBob3cgdGhlIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGEgYXJlIG1hcHBlZCB0byB0aGUgdmlzdWFsICdhZXN0aGV0aWNzJyB5b3Ugc2VlIGluIHlvdXIgcGxvdCAoaGVyZSwgbWFwcGluZyBkYXRlIHRvIHRoZSB4LWF4aXMsIHdlaWdodCB0byB0aGUgeS1heGlzLCBhbmQgY29sb3IgdG8gdmFyaWV0eSkKKiBbZ2VvbWV0cmllcyBvciAiZ2VvbXMiXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvaW5kZXguaHRtbCNnZW9tcyk6IHRlbGwgUiB3aGF0IHR5cGUgb2YgcGxvdCB5b3Ugd2FudCB0byBtYWtlLCB0eXBpY2FsbHkgc3RhcnQgYGdlb21fYCAoaGVyZSwgYGdlb21fbGluZSgpYCB0byBtYWtlIGEgbGluZSBwbG90LCBhbmQgcmVtaW5kZXIsIHlvdSBkb24ndCBuZWVkIHRvIHBpY2sganVzdCBvbmUhKQoqIFtzY2FsZXNdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS8jc2NhbGVzKTogY29udHJvbCBob3cgdGhlIHZhcmlhYmxlcyBhcmUgcmVsYXRlZCB0byB0aGUgdmlzdWFsIHByb3BlcnRpZXMgKGhlcmUsIHdlIGFyZSB1c2luZyBgc2NhbGVfY29sb3JfZGlzY3JldGVfZCgpYCB0byBzZXQgdGhlIGNvbG9ycyBmb3IgdGhlIHBsb3QpCiogW2ZhY2V0c10oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlLyNmYWNldHRpbmcpOiBnZW5lcmF0ZXMgc21hbGwgbXVsdGlwbGVzIG9mIHBsb3RzIGFsbG93aW5nIGVhc3kgdmlzdWFsIGNvbXBhcmlzb24gKGhlcmUsIG1ha2luZyBzbWFsbCBsaW5lIHBsb3RzIGZvciBlYWNoIHZhcmlldHkgdXNpbmcgYGZhY2V0X3dyYXAoKWApCiogW2Nvb3JkaW5hdGVzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvI2Nvb3JkaW5hdGUtc3lzdGVtcyk6IGNvbnRyb2xzIGhvdyB4IGFuZCB5IGFyZSB2aXN1YWxpemVkIGluIHlvdXIgcGxvdCAoaGVyZSwgdXNpbmcgYGNvb3JkX2NhcnRlc2lhbigpYCB3aGljaCBpcyBhY3R1YWxseSB0aGUgZGVmYXVsdCwgd2hpY2gganVzdCBwbG90cyBhcyBDYXJ0ZXNpYW4gY29vcmRpbmF0ZXMpCiogW2xhYmVsc10oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlLyNsYWJlbHMpOiBhZGp1c3RpbmcgaG93IHRoZSBsYWJlbHMgb2YgdGhlIHBsb3RzIGxvb2sgKGhlcmUsIGxhYmVsaW5nIHRoZSB4IGFuZCB5IGF4aXMsIHByb3ZpZGluZyBhIHRpdGxlIGFuZCBhIHN1YnRpdGxlKQoqIFt0aGVtZV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlLyN0aGVtZXMpOiBjb250cm9sbGluZyB0aGUgbm9uLWRhdGEgcGFydHMgb2YgeW91ciBwbG90cyAoaGVyZSwgdXNpbmcgYm90aCBgdGhlbWVfbWluaW1hbCgpYCB3aGljaCBwcm92aWRlcyBhbiBvdmVyYWxsIHRoZW1lLCBhbmQgdXNpbmcgYHRoZW1lKClgIHRvIHJlbW92ZSB0aGUgbGVnZW5kIHdoaWNoIHdlIGRvbid0IG5lZWQgYmVjYXVzZSB3ZSBoYXZlIGZhY2V0cykKCiMgU3ludGF4CkxldCdzIGdvIHRocm91Z2ggdGhlIHN5bnRheCBpbiBtb3JlIGRldGFpbCBub3cuIEkgYW0gZ29pbmcgdG8gaW50cm9kdWNlIGFsbCB0aGUgc3ludGF4LCB0aGVuIHdlIHdpbGwgZm9jdXMgdGhpcyB3ZWVrIHRocm91Z2ggZ2VvbXMsIGFuZCBkbyB0aGUgcmVzdCBuZXh0IHdlZWsuIEkgd2FudCB0byBnaXZlIHlvdSBhbiBvdmVydmlldyBvZiB3aGF0IHlvdSBjYW4gZG8gd2l0aCBnZ3Bsb3QsIHRoZW4gd2Ugd2lsbCBnZXQgaW50byBtb3JlIGRldGFpbC4KCiMjIERhdGEKVGhlIGZpcnN0IGFyZ3VtZW50IHBhc3NlZCB0byB5b3VyIHBsb3QgaXMgdGhlIGRhdGEuIEhvdyBkaWQgSSBrbm93IHRoYXQ/IEl0J3MgaW4gdGhlIGRvY3VtZW50YXRpb24uCmBgYHtyIGdncGxvdCBoZWxwfQo/Z2dwbG90KCkKYGBgCgpUaGUgc2ltcGxlc3QgZ2dwbG90IGNvZGUgeW91IGNhbiB3cml0ZSwganVzdCB1c2luZyB0aGUgYGdncGxvdCgpYCBmdW5jdGlvbiBhbmQgaW5kaWNhdGluZyB0aGUgZGF0YSB3ZSB3YW50IHRvIHVzZS4gQmVjYXVzZSBkYXRhIGlzIHRoZSBkZWZhdWx0IGZpcnN0IGFyZ3VtZW50LCB5b3UgY2FuIGFjdHVhbGx5IG9taXQgdGhlIGBkYXRhID1gIHBhcnQgb2YgdGhpcyBjb2RlIGFuZCBpdCB3aWxsIHdvcmsganVzdCB0aGUgc2FtZS4KYGBge3IgZGF0YSBvbmx5fQpnZ3Bsb3QoZGF0YSA9IGdhcmRlbl9oYXJ2ZXN0KQpgYGAKCldoeSBkbyB3ZSBub3Qgc2VlIGEgcGxvdD8gV2VsbCB3ZSBoYXZlbid0IHRvbGQgUiB3aGF0IHRvIHBsb3QhIFdlIGFyZSBnZXR0aW5nIHRoZSBmaXJzdCAiYmFzZSIgbGF5ZXIgb2YgdGhlIHBsb3QuCgpGb3IgdGhvc2Ugb2YgeW91IHdobyBhcmUgZmFtaWxpYXIgd2l0aCB0aGUgdGlkeXZlcnNlIHBpcGUgYCU+JWAsIHlvdSBjYW4gYWxzbyBwaXBlIHRoZSBkYXRhIHRvIHRoZSBnZ3Bsb3QgZnVuY3Rpb24uIFdoZW4gcmVhZGluZyBjb2RlLCB5b3UgY2FuIGludGVycHJldCB0aGUgcGlwZSBhcyAiYW5kIHRoZW4uIiBIZXJlLCB0YWtlIHRoZSBgZ2FyZGVuX2hhcnZlc3RgIGRhdGEsIGFuZCB0aGVuLCBydW4gYGdncGxvdCgpYC4gV3JpdGluZyBjb2RlIGluIHRoaXMgd2F5IGlzIG15IHByZWZlcmVuY2Ugc28gSSB0ZW5kIHRvIGNvZGUgbGlrZSB0aGlzLgpgYGB7ciBkYXRhIGFuZCBwaXBlfQpnYXJkZW5faGFydmVzdCAlPiUgCiAgZ2dwbG90KCkKYGBgCgpTdGlsbCBub3RoaW5nLiBXZWxsIHRoYXQncyB3aGF0IHdlIHdvdWxkIGV4cGVjdC4KCiMjIEFlc3RoZXRpYyBtYXBwaW5ncyBgYWVzKClgCk5vdyB0aGF0IHdlJ3ZlIGluZGljYXRlZCBvdXIgZGF0YSwgd2UgY2FuIGFkZCBhZXN0aGV0aWNzIG1hcHBpbmcgc28gd2UgY2FuIHdvcmsgdG93YXJkcyBhY3R1YWxseSBzZWUgYSBwbG90LiBXZSB3YW50IHRvIG1ha2UgYSBsaW5lIHBsb3Qgd2hlcmUgb24gdGhlIHgtYXhpcyB3ZSBoYXZlIHRoZSBkYXRlIChgZGF0ZWApLCBhbmQgb24gdGhlIHktYXhpcyB3ZSBoYXZlIGhvdyBtdWNoIHRvbWF0byB3YXMgaGFydmVzdGVkIChgd2VpZ2h0YCkuCmBgYHtyIGFlc30KZ2FyZGVuX2hhcnZlc3RfdG9tYXRvICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB3ZWlnaHQpKQpgYGAKClNvIHdlIGhhdmUgcHJvZ3Jlc3NlZCBmcm9tIGEgYmxhbmsgcGxvdCwgYnV0IHdlIHN0aWxsIGRvIG5vdCBoYXZlIGEgcGxvdCBieSBiYXNpY2FsbHkgYW55b25lJ3MgZGVmaW50aW9uLiBXaHkgbm90PwoKRXZlbiB0aG91Z2ggd2UgaGF2ZSBpbmRpY2F0ZWQgdG8gUiBvdXIgZGF0YSBhbmQgYWVzdGhldGljIG1hcHBpbmdzLCB3ZSBoYXZlIG5vdCBpbmRpY2F0ZWQgd2hhdCBwcmVjaXNlbHkgdG8gZG8gd2l0aCBvdXIgZGF0YS4gV2UgaGF2ZSBzYWlkIHdoYXQgd2Ugd2FudCBvbiB4IGFuZCB5IChhbmQgbm93IHdlIGNhbiBzZWUgdGhvc2UgbGFiZWxsZWQgYXBwZWFyaW5nKSBidXQgd2UgaGF2ZSBub3QgaW5kaWNhdGVkIHdoYXQgKnR5cGUqIG9mIHBsb3Qgd2Ugd2FudC4gQW5kLCB3ZSBjYW4gZG8gdGhhdCBpbiB0aGUgbmV4dCBzdGVwLCBieSBhZGRpbmcgYSBgZ2VvbV9gLgoKIyMgR2VvbXMgYGdlb21fYAoKTm93IGxldCdzIGluZGljYXRlIHdoYXQgdHlwZSBvZiBwbG90IHdlIHdhbnQuIEluIHRoaXMgZXhhbXBsZSwgd2UgYXJlIGdvaW5nIHRvIG1ha2UgYSBsaW5lIHBsb3QsIGFuZCB0byBkbyB0aGF0IHdlIHdpbGwgdXNlIFtgZ2VvbV9saW5lKClgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9wYXRoLmh0bWwpCmBgYHtyIGdlb20gbGluZX0KZ2FyZGVuX2hhcnZlc3RfdG9tYXRvICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB3ZWlnaHQpKSArCiAgZ2VvbV9saW5lKCkKYGBgCgpXZSBoYXZlIGEgcGxvdCEgSXQncyBub3QgYSByZWFsbHkgZ29vZCBwbG90LCBidXQgaXRzIGEgcGxvdCBhbmQgd2UgY2FuIHdvcmsgZnJvbSBoZXJlLgoKWW91IGNhbiBzZWUgdGhhdCB3aGF0IFIgaGFzIGRvbmUgaXMgdGFrZSBlYWNoIGRhdGUsIGFuZCBwbG90dGVkIHRoZSB0b3RhbCB3ZWlnaHQgb2YgdG9tYXRvZXMgaGFydmVzdGVkIG9uIHRoYXQgZGF5LiBXaGF0IHdlIGNhbiBzZWUgZnJvbSB0aGlzIHBhcnQgaXMgdGhhdCBpbiB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzZWFzb24sIHRoZXJlIGlzIGxpdHRsZSB0b21hdG8gcHJvZHVjdGlvbiAodGhpcyBpcyBub3Qgc3VycHJpc2luZyB0byBhbnlvbmUgd2hvIGtub3dzIGFib3V0IGhvcnRpY3VsdHVyZSBvciBoYXMgZ3Jvd24gdG9tYXRvZXMgYmVmb3JlKSwgYW5kIHByb2R1Y3Rpb24gaW5jcmVhc2VzIGFzIHRoZSBzZWFzb24gcHJvZ3Jlc3Nlcy4gV2UgZG9uJ3Qgc2VlIGFueSBoYXJ2ZXN0IGFmdGVyIG1pZC1PY3RvYmVyIHdoaWNoIG1ha2VzIHNlbnNlIGJlY2F1c2UgRHIuIExlbmR3YXkgbGl2ZXMgaW4gTWlubmVzb3RhIGFuZCBwcm9iYWJseSB0aGVyZSB3YXMgYSBmcm9zdCB0aGF0IGtpbGxlZCB0aGUgcGxhbnRzIChoZW5jZSBubyBtb3JlIPCfjYUpLgoKQSBub3RlIGFib3V0IGFlc3RoZXRpYyBtYXBwaW5ncyBub3cgdGhhdCB3ZSBoYXZlIGludHJvZHVjZWQgZ2VvbXMgLWBhZXMoKWAgY2FuIGdvIGluIHR3byBwbGFjZXM6CgoqIGluIHRoZSBgZ2dwbG90KClgIGNhbGwsIGFuZCB0aGlzIG1lYW5zIHRoZXkgd2lsbCBpbmhlcml0IGZvciBldmVyeSBsYXllciBvZiB0aGUgcGxvdAoqIGluIGEgc3BlY2lmaWMgYGdlb21fYCwgYW5kIHRob3NlIGFlc3RoZXRpY3Mgd2lsbCBvbmx5IGJlIGZvciB0aGF0IHNwZWNpZmljIGdlb20uCgpTbyB3ZSBjYW4gbWFrZSB0aGUgc2FtZSBwbG90IHdlIHNhdyBhYm92ZSBieSBtYXBwaW5nIGFlc3RoZXRpY3Mgd2l0aGluIGBnZW9tX2xpbmUoKWAuIApgYGB7ciBnZW9tIGxpbmU7IGxvY2FsIGFlc30KZ2FyZGVuX2hhcnZlc3RfdG9tYXRvICU+JQogIGdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkYXRlLCB5ID0gd2VpZ2h0KSkKYGBgCgpMZXQncyBzYXkgd2Ugd2FudGVkIHRvIHNlZSBob3cgdGhlIGhhcnZlc3Qgb2YgZGlmZmVyZW50IHZhcmlldGllcyBsb29rcyBvdmVyIHRoZSBzdW1tZXI/IFdlIGNhbiB0YWtlIHRoZSB2YXJpYWJsZSBgdmFyaWV0eWAgYW5kIG1hcCBpdCB0byB0aGUgYWVzdGhldGljIGBjb2xvcmAuCmBgYHtyIGFlcyBjb2xvcn0KZ2FyZGVuX2hhcnZlc3RfdG9tYXRvICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB3ZWlnaHQsIGNvbG9yID0gdmFyaWV0eSkpICsKICBnZW9tX2xpbmUoKQpgYGAKClRoaXMgaXMgdGlsbCBub3QgYSBiZWF1dGlmdWwgcGxvdCwgYnV0IHlvdSBhcmUgYWJsZSB0byBzZWUgbm93IGhvdyB5b3UgY2FuIG1hcCBhIHZhcmlhYmxlIG9mIHRoZSBkYXRhIChoZXJlLCBgdmFyaWV0eWApIHRvIGFuIGFlc3RoZXRpYyAoYGNvbG9yYCkuCgpBbm90aGVyIGltcG9ydGFudCB0aGluZyB0byBub3RpY2UgaGVyZSBpcyB0aGF0IG5vdyB0aGUgZGF0YSBpcyBncm91cGVkIGJ5IHZhcmlldHkuIFdlIGFyZSBzZWVpbmcgMTIgbGluZXMgaW5zdGVhZCBvZiAxLiBUaGlzIGhhcHBlbnMgYXV0b21hdGljYWxseSB1bmRlciB0aGUgaG9vZC4gVGhpcyAnZ3JvdXBpbmcnIHdpbGwgYmUgbWFpbnRhaW5lZCBhY3Jvc3MgYWRkaXRpb25hbCBnZW9tcyBiZWNhdXNlIGl0IGlzIGluIHRoZSBnbG9iYWwgYWVzdGhldGljIG1hcHBpbmdzIGZvciB0aGUgcGxvdC4KCldlIGNhbiBhbHNvIGFkZCBtb3JlIHRoYW4gb25lIGdlb20uIExldCdzIHRyeSBhZGRpbmcgYGdlb21fcG9pbnQoKWAgc28gd2UgY2FuIGJldHRlciBzZWUgZXhhY3RseSB3aGljaCB0aW1lcyB3ZXJlIHNhbXBsZWQgaW4gdGhpcyBkYXRhc2V0LgoKYGBge3IgZ2VvbV9wb2ludH0KZ2FyZGVuX2hhcnZlc3RfdG9tYXRvICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB3ZWlnaHQsIGNvbG9yID0gdmFyaWV0eSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKVG8gbW9yZSBmdWxseSBtYWtlIHRoZSBwb2ludCBhYm91dCBnbG9iYWwgdnMgYWVzdGhldGljIG1hcHBpbmdzLCBsZXQncyBsb29rIGF0IGFuIGV4YW1wbGUuCmBgYHtyIGdlb20gcG9pbnQgd2l0aG91dCBhZXN9CmdhcmRlbl9oYXJ2ZXN0X3RvbWF0byAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gd2VpZ2h0KSkgKwogIGdlb21fbGluZShhZXMoY29sb3IgPSB2YXJpZXR5KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCkhlcmUsIHdlIGNhbiBzZWUgdGhhdCBob3cgdGhlIGxpbmUgbGF5ZXIgaXMgYmVpbmcgZ3JvdXBlZCBieSB2YXJpZXR5LCB3aGlsZSB0aGUgcG9pbnRzIGFyZSBub3QuIFRoaXMgaXMgYmVjYXVzZSB0aGUgYWVzdGhldGljIG1hcHBpbmdzIGZvciBvbmUgZ2VvbSBkb24ndCBpbmhlcml0IHRvIHRoZSBuZXh0IG9uZS4gSWYgd2Ugd2FudCB0byBhbHNvIGNvbG9yIHBvaW50cyBieSB2YXJpZXR5LCB3ZSBuZWVkIHRvIGVpdGhlciAxKSBzZXQgdGhpcyBhcyB0aGUgZ2xvYmFsIGFlc3RoZXRpYyBtYXBwaW5nIG9yIDIpIGFsc28gc2V0IGBhZXMoY29sb3IgPSB2YXJpZXR5KWAgaW4gYGdlb21fcG9pbnQoKWAgdG9vLgoKYGBge3IgbGluZSBhbmQgcG9pbnQgbG9jYWwgYWVzfQpnYXJkZW5faGFydmVzdF90b21hdG8gJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHdlaWdodCkpICsKICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gdmFyaWV0eSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHZhcmlldHkpKQpgYGAKCgojIyMgTWFwcGluZyB2cy4gJ3NldHRpbmcnCgpJZiB5b3Ugd2FudCB0byBtYXAgYSB2YXJpYWJsZSB0byBhbiBhZXN0aGV0aWMsIGl0IE1VU1QgYmUgd2l0aGluIHRoZSBgYWVzKClgIHN0YXRlbWVudC4gSWYgeW91IGp1c3Qgd2FudCB0byBjaGFuZ2UgdGhlIGNvbG9yIHRvICJibHVlIiBmb3IgZXhhbXBsZSwgaXQgc2hvdWxkIGJlIG91dHNpZGUgdGhlIGBhZXMoKWAgc3RhdGVtZW50LiBMb29rIGF0IHRoZSBkaWZmZXJlbmNlLgpgYGB7ciBzZXR0aW5nIGNvbG9yfQpnYXJkZW5faGFydmVzdF90b21hdG8gJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHdlaWdodCkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiYmx1ZSIpCmBgYAoKPiAqKnRsOmRyKiogaWYgbWFwcGluZyBhIHZhcmlhYmxlIHRvIGFuIGFlc3RoZXRpYywgaW5zaWRlIGBhZXMoKWAsIGlmIG5vdCwgdGhlbiBvdXRzaWRlLgoKIyMjIE1vcmUgYWJvdXQgYWVzdGhldGljcwpJdCdzIGhhcmQgdG8gdGFsayBhYm91dCBob3cgdG8gbWFwIHRvIGFlc3RoZXRpY3MgYmVmb3JlIHlvdSBhZGQgYSBnZW9tLCB3aGljaCBpcyB3aHkgdGhpcyBjb250ZW50IGlzIGluIHRoaXMgc2VjdGlvbi4KClNvIGZhciB3ZSBoYXZlIHRhbGtlZCBhYm91dCBtYXBwaW5nIGFlc3RoZXRpY3MgdG8gYHhgLCBgeWAsIGFuZCBgY29sb3JgLiBCZWxvdyBpcyBhIFtsaXN0IG9mIG90aGVyIGFlc3RoZXRpY3NdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL2FydGljbGVzL2dncGxvdDItc3BlY3MuaHRtbCkgeW91IGNhbiBtYXAgdG86CgojIyMjIGBjb2xvcmAgKG9yIGBjb2xvdXJgIGlmIHRoYXQgc3VpdHMgeW91IGJldHRlcikgYW5kIGBmaWxsYApJbiBnZW5lcmFsIGNvbG9yIGNvbnRyb2xzIHRoZSBvdXRzaWRlL2xpbmUsIGFuZCBmaWxsIGNvbnRyb2xzIHRoZSBpbnNpZGUgb2YgYSBzaGFwZS4gU29tZSBnZW9tcyB3aWxsIHdvcmsgb25seSB3aXRoIGBjb2xvcmAgb3IgYGZpbGxgLCBhbmQgd29yayB3aXRoIGJvdGguIFRoZXJlIGFyZSBhIG1pbGxpb25zIHdheXMgdG8gY29udHJvbCB0aGUgY29sb3IsIGluY2x1ZGluZyBieSB1c2luZyB0aGUgW1IgY29sb3IgbmFtZXNdKGh0dHBzOi8vd3d3LmRhdGFub3ZpYS5jb20vZW4vYmxvZy9hd2Vzb21lLWxpc3Qtb2YtNjU3LXItY29sb3ItbmFtZXMvKSAoZG9uJ3QgZm9yZ2V0IHRvIHB1dCB0aGVtIGluIHF1b3RlcyksIG9yIGhleCBjb2RlcyAoZS5nLiwgIkZGMDAwMCIgZm9yIHJlZCkuIFRoZXJlIGFyZSBhIHRvbiBvZiBkaWZmZXJlbnQgY29sb3IgcGFsZXR0ZXMgaW4gUiBsaWtlIFtjb2xvciBicmV3ZXJdKGh0dHBzOi8vci1ncmFwaC1nYWxsZXJ5LmNvbS8zOC1yY29sb3JicmV3ZXJzLXBhbGV0dGVzLmh0bWwpIGFuZCBJJ2QgcmVjb21tZW5kIHlvdSB0byB0aGluayBhYm91dCB1c2luZyBjb2xvcnMgdGhhdCBhcmUgY29sb3IgYmxpbmQgZnJpZW5kbHkgbGlrZSBbdmlyaWRpc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCkuIFBpY2tpbmcgYSBjb2xvciBwYWxldHRlIGFsbG93cyBjb250aW51aXR5IGFjcm9zcyB5b3VyIHByZXNlbnRhdGlvbi9tYW51c2NyaXB0LCBhbmQgY2FuIGhlbHAgaW4gdGhlIGludGVycHJldGF0aW9uIG9mIHlvdXIgZGF0YSAoZS5nLiwgaGF2aW5nIGEgZGl2ZXJnZW50IHNjYWxlIHdoZXJlIGRhcmtlciBtZWFucyBtb3JlIGFidW5kYW50LCBvciBwYWlyaW5nIGNvbG9ycyBsaWtlIGxpZ2h0IGFuZCBtZWRpdW0gYmx1ZSB0byBpbmRpY2F0ZSB3aGljaCBzYW1wbGVzIGhhdmUgc29tZSBraW5kIG9mIHJlbGF0aW9uc2hpcCkuCgojIyMjIGBsaW5ldHlwZWAKWW91IGNhbiBjaGFuZ2UgdGhlIHN0eWxlIG9mIGEgbGluZSBiYXNlZCBvbiBhIHZhcmlhYmxlCmBgYHtyIGFlcyBsaW5ldHlwZX0KZ2FyZGVuX2hhcnZlc3RfdG9tYXRvICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB3ZWlnaHQpKSArCiAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZSA9IHZhcmlldHkpKQpgYGAKCldvdyB0aGlzIGlzIGEgZGlzYXN0ZXIgYnV0IHlvdSBjYW4gc2VlIHRoZSBwb2ludCBhYm91dCBtYXBwaW5nIHZhcmlhYmxlcyB0byBsaW5ldHlwZS4KCkhlcmUgYXJlIHNvbWUgZGlmZmVyZW50IGxpbmV0eXBlcyB5b3UgY2FuIHNlbGVjdCBmcm9tOgoKYGBge3IgbGluZXR5cGVzLCBmaWcuYWx0ID0gIkFuIGltYWdlIG9mIDYgZGlmZmVyZW50IHR5cGVzIG9mIGxpbmVzLCBzb2xpZCBsaW5lLCBkYXNoZWQgbGluZSwgZG90dGVkIGxpbmUgKHdoaWNoIGhhcyBzbWFsbGVyIGRvdHMgdGhhbiBkYXNoZWQpLCBkb3RkYXNoICh3aGljaCBpcyBvbmUgZG90IHRoZW4gb25lIGRhc2gpLCBsb25nZGFzaCAod2hpY2ggaGFzIGxvbmdlciBkYXNoZXMgYW5kIHNtYWxsZXIgc3BhY2UgYmV0d2VlbiB0aGUgZGFzaGVzKSwgYW5kIHR3b2Rhc2ggKHdoaWNoIGlzIGxpa2UgZG90ZGFzaCBidXQgdGhlIGRhc2hlcyBhcmUgbG9uZ2VyKSIsIGZpZy5jYXA9ICJGaWd1cmUgZnJvbSBbZ2dwbG90IGRvY3VtZW50YXRpb25dKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL2FydGljbGVzL2dncGxvdDItc3BlY3MuaHRtbCNsaW5lcykiLCBvdXQud2lkdGggPSAiNzAlIiwgZmlnLmFsaWduID0gImNlbnRlciIsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9saW5ldHlwZXMucG5nIikKYGBgCgojIyMjIGBzaXplYApZb3UgY2FuIGFsc28gbWFwIHZhcmlhYmxlcyB0byBgc2l6ZWAuIFRoaXMgY291bGQgYmUgdXNlZnVsIGlmIHlvdSB3YW50ZWQgdG8gc2F5IG1ha2UgeW91ciBwb2ludHMgYmlnZ2VyIHdoZW4gYSBmb2xkIGNoYW5nZSBpcyBiaWdnZXIsIG9yIGJpZ2dlciB3aGVuIGEgdmFsdWUgaXMgbW9yZSBzaWduaWZpY2FudC4gQmVsb3cgaXMgYW4gZXhhbXBsZSBvZiBtYXBwaW5nIHdlaWdodCB0byBgc2l6ZWAgaW4gb3VyIGV4YW1wbGUgZGF0YXNldC4KCmBgYHtyIGFlcyBzaXplfQpnYXJkZW5faGFydmVzdF90b21hdG8gJT4lCiAgZmlsdGVyKHZhcmlldHkgJWluJSBjKCJNb3J0Z2FnZSBMaWZ0ZXIiLCAiQnJhbmR5d2luZSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB2YXJpZXR5LCB5ID0gZGF0ZSwgc2l6ZSA9IHdlaWdodCkpICsKICBnZW9tX3BvaW50KCkKYGBgCgojIyMjIGBzaGFwZWAKWW91IGNhbiBhbHNvIG1hcCB2YXJpYWJsZXMgdG8gc2hhcGUuIFRoaXMgY291bGQgYmUgdXNlZnVsIGlmIHlvdSB3YW50IHBvaW50cyBvZiBvbmUgdHJlYXRtZW50IG9uIGEgc2NhdHRlcnBsb3QgdG8gYmUgY2lyY2xlcywgYSBzZWNvbmQgdHJlYXRtZW50IHRyaWFuZ2xlcywgZXRjLiBZb3UgY2FuIGNvbWJpbmUgbWFwcGluZyB0byBzaGFwZSBhbmQgY29sb3IgdG9nZXRoZXIgd2hpY2ggaXMgZ29vZCBmb3IgdGhvc2Ugd2hvIGFyZSBjb25jZXJuZWQgYWJvdXQgYmxhY2sgYW5kIHdoaXRlIHByaW50YWJpbGl0eSwgYnV0IGFsc28gZWFzeSBkaWZmZXJlbnRpYWJpbGl0eSB3aGVuIHZpZXdlZCBvbiBhIGNvbXB1dGVyLgoKYGBge3Igc2hhcGVzLCBmaWcuYWx0ID0gIkFuIGltYWdlIG9mIHRoZSAyNiBzaGFwZXMgYnkgbnVtYmVyICgwLTI1KSBpbiBSLiIsIGZpZy5jYXA9ICJGaWd1cmUgZnJvbSBbc3RoZGFdKGh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvd2lraS9nZ3Bsb3QyLXBvaW50LXNoYXBlcykiLCBvdXQud2lkdGggPSAiNzAlIiwgZmlnLmFsaWduID0gImNlbnRlciIsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9zaGFwZXMucG5nIikKYGBgCgpTaGFwZXMgMC0yMCBhY2NlcHQgb25seSBhIGBjb2xvcmAgYWVzdGhldGljcy4gU2hhcGVzIDIxLTI1IGFjY2VwdCBib3RoIGEgYGNvbG9yYCBhbmQgYGZpbGxgIGFlc3RoZXRpYywgd2hlcmUgYGNvbG9yYCBjb250cm9scyB0aGUgY29sb3Igb2YgdGhlIG91dHNpZGUgb2YgdGhlIHNoYXBlLCBhbmQgYGZpbGxgIGNvbnRyb2xzIHRoZSBjb2xvciBvZiB0aGUgaW5zaWRlIG9mIHRoZSBzaGFwZS4gSSBiYXNpY2FsbHkgYWx3YXlzIHVzZSBzaGFwZXMgMjEtMjUuCgojIyMjIGBhbHBoYWAKU2V0dGluZyBgYWxwaGFgIGFsbG93cyB5b3UgdG8gbWFwIGEgdmFyaWFibGUgdG8gdGhlIHRyYW5zcGFyZW5jeSBvZiBhIHBhcnQgb2YgeW91ciBwbG90LiBTbyBmb3IgZXhhbXBsZSwgaWYgeW91IGhhZCBhIGNvcnJlbGF0aW9uIHBsb3QsIHlvdSBjb3VsZCBtYWtlIGEgc3Ryb25nIGNvcnJlbGF0aW9uIHJlYWxseSBkYXJrLCB3aGlsZSBhIHdlYWsgcmVsYXRpb25zaGlwIGxpZ2h0ZXIuIEFscGhhIGNhbiByYW5nZSBiZXR3ZWVuIDAgYW5kIDEsIHdoZXJlIDAgaXMgdG90YWxseSB0cmFuc3BhcmVudCwgYW5kIDEgaXMgY29tcGxldGVseSBvcGFxdWUuIAoKIyMgU2NhbGVzIGBzY2FsZV9gClVzaW5nIHNjYWxlcyBhbGxvd3MgeW91IHRvIGNvbnRyb2wgaG93IHRoZSBkYXRhIGFyZSBsaW5rZWQgdG8gdGhlIHZpc3VhbCBwcm9wZXJ0aWVzIG9mIHlvdXIgcGxvdC4KClNjYWxlcyBhbGxvdyB5b3UgdG8gcGljayBjb2xvcnMsIHNoYXBlcywgYWxwaGFzLCBsaW5lcywgdHJhbnNmb3JtYXRpb25zIChlLmcuIHNjYWxpbmcgeW91ciBheGVzIHRvIGEgbG9nIHNjYWxlKSwgYW5kIG90aGVycy4gWW91IGNhbiBhbHNvIHVzZSBzY2FsZXMgdG8gc2V0IHRoZSBsaW1pdHMgb2YgeW91ciBwbG90cy4KCiMjIEZhY2V0cyBgZmFjZXRfd3JhcCgpYCBhbmQgYGZhY2V0X2dyaWQoKWAKRmFjZXRpbmcgYWxsb3dzIHlvdSB0byBsb29rIGF0IHlvdXIgcGxvdHMgdXNpbmcgc21hbGwgbXVsdGlwbGVzLCB0byBjb21wYXJlIHBsb3RzIHRoYXQgbWlnaHQgYmUgb3RoZXJ3aXNlIGNyb3dkZWQgb3IgaGFyZCB0byBpbnRlcnByZXQuIAoKRmFjZXRpbmcgY2FuIGJlIGRvbmUgdXNpbmcgYGZhY2V0X3dyYXAoKWAgb3IgYGZhY2V0X2dyaWQoKWAuCgojIyBDb29yZGluYXRlcyBgY29vcmRfYApPZnRlbiB0aGUgY29vcmRpbmF0ZSBzeXN0ZW0gdXNlZCBmb3IgeW91ciBwbG90IHdpbGwgYmUgYSBzaW1wbGUgQ2FydGVzaWFuIHN5c3RlbSB1c2luZyB4IGFuZCB5LiBCdXQgc29tZXRpbWVzLCBsaWtlIGZvciBtYWtpbmcgbWFwcyBvciBvdGhlciBzcGVjaWFsaXplZCBwbG90cywgeW91IHdpbGwgd2FudCB0byBjaGFuZ2UgaG93IHggYW5kIHkgbWFwIHRvIHlvdXIgY29vcmRpbmF0ZSBzeXN0ZW0uCgojIyBMYWJlbHMgYGxhYnMoKWAKSGF2aW5nIGdvb2QgbGFiZWxzIGhlbHBzIHlvdXIgcmVhZGVyIChhbmQgeW91LCB3aGVuIHlvdSBjb21lIGJhY2sgdG8gdGhlIHBsb3QgaW4gdGhlIGZ1dHVyZSkgdW5kZXJzdGFuZCB3aGF0IGl0cyBhbGwgYWJvdXQuIAoKSW4gdGhlIGBsYWJzKClgIGZ1bmN0aW9uLCB5b3UgY2FuIGluZGljYXRlOgoKKiBgeGAgZm9yIHRoZSB4LWF4aXMgbGFiZWwKKiBgeWAgZm9yIHRoZSB5LWF4aXMgbGFiZWwKKiBgdGl0bGVgIGZvciBhIHRpdGxlCiogYHN1YnRpdGxlYCBmb3IgYSBzdWJ0aXRsZSB1bmRlcm5lYXRoIHlvdXIgdGl0bGUKKiBgY2FwdGlvbmAgZm9yIGEgY2FwdGlvbgoKSW4gYHRoZW1lKClgIHlvdSBjYW4gY2hhbmdlIGNoYXJhY3RlcmlzdGljcyBvZiB0aGVzZSBsYWJlbHMgbGlrZSB0aGVpciBzaXplLCBmb250cywganVzdGZpY2F0aW9uLCBldGMuCiAKIyMgVGhlbWVzIGB0aGVtZSgpYCBhbmQgYHRoZW1lX2AKVGhlbWVzIHdpbGwgY29udHJvbCBhbGwgdGhlIG5vbi1kYXRhIHBhcnRzIG9mIHlvdXIgcGxvdC4gVGhlcmUgYXJlIHNvbWUgcHJlLXNldCAiY29tcGxldGUiIHRoZW1lcyB0aGF0IHlvdSBjYW4gcmVjb2duaXplIGFzIHRoZXknbGwgYmUgY2FsbGVkIGB0aGVtZV9YWFgoKWAsIGFuZCB5b3UgY2FuIGFkanVzdCBhbnkgdGhlbWUgcGFyYW1ldGVycyBieSBzZXR0aW5nIHBhcmFtZXRlcnMgd2l0aGluIGB0aGVtZSgpYC4gVGhlcmUgYXJlIHByb2JhYmx5IDUwIHBhcmFtZXRlcnMgeW91IGNhbiBzZXQgd2l0aGluIGB0aGVtZSgpYCBhbmQgdGhleSBpbmNsdWRlIHRleHQgc2l6ZSwgYXhpcyBsYWJlbCBvcmllbnRhdGlvbiwgdGhlIHByZXNlbmNlIG9mIGEgbGVnZW5kLCBhbmQgbWFueSBvdGhlcnMuIAoKIyBJbiBjbGFzcwoKSW4gY2xhc3MsIHdlIHdpbGwgcHJhY3RpY2UgdXNpbmcgZ2dwbG90LCBlc3BlY2lhbGx5IHBsYXlpbmcgYXJvdW5kIHdpdGggd3JpdGluZyBzeW50YXggYW5kIGludmVzZXRpZ2F0aW5nIGRpZmZlcmVudCBnZW9tcy4gQ2xpY2sgW2hlcmVdKDA0X2dncGxvdF9yZWNpdGF0aW9uLmh0bWwpIGZvciB0aGUgcmVjaXRhdGlvbiBtYXRlcmlhbHMuCgojIFVzZWZ1bCByZXNvdXJjZXM6CgotICAgW2BnZ3Bsb3QyYCBjaGVhdHNoZWV0XShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcnN0dWRpby9jaGVhdHNoZWV0cy9tYWluL2RhdGEtdmlzdWFsaXphdGlvbi5wZGYpCi0gICBbYGdncGxvdDJgIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLykKLSAgIFtnZ3Bsb3QyOiBlbGVnYW50IGdyYXBoaWNzIGZvciBkYXRhIGFuYWx5c2lzIGJ5IEhhZGxleSBXaWNraGFtXShodHRwczovL2dncGxvdDItYm9vay5vcmcvaW5kZXguaHRtbCkKLSAgIFtBIHJlYWxseSBjb21wZWhlbnNpdmUgbGlzdCBvZiByZXNvdXJjZXMgY29tcGlsZWQgYnkgRXJpayBHYWhuZXIgTGFyc2VuXShodHRwczovL2dpdGh1Yi5jb20vZXJpa2dhaG5lci9hd2Vzb21lLWdncGxvdDIpCi0gUGFzdCBnZ3Bsb3QgQ29kZSBDbHViczoKCiAgKiBbVmlzdWFsaXppbmcgRGF0YSBieSBNaWNoYWVsIEJyb2VdKGh0dHBzOi8vYmlvZGFzaC5naXRodWIuaW8vY29kZWNsdWIvMDRfZ2dwbG90Mi8pCiAgKiBbZ2dwbG90IHJvdW5kIDIgYnkgbWVdKGh0dHBzOi8vYmlvZGFzaC5naXRodWIuaW8vY29kZWNsdWIvMDVfZ2dwbG90LXJvdW5kLTIvKQogICogW0ZhY2V0aW5nLCBtdWx0aS1wbG90cywgYW5kIGFuaW1hdGluZ10oaHR0cHM6Ly9iaW9kYXNoLmdpdGh1Yi5pby9jb2RlY2x1Yi8xMF9mYWNldGluZy1hbmltYXRpbmcvKQogICogW1Zpc3VhbGl6aW5nIERhdGEgYnkgTWljaGFlbCBCcm9lIGEgc2Vjb25kIG9uZV0oaHR0cHM6Ly9iaW9kYXNoLmdpdGh1Yi5pby9jb2RlY2x1Yi9zMDJlMDZfZ2dwbG90Mi8pCiAgKiBbZ2dwbG90IHJvdW5kIDIgYSBzZWNvbmQgb25lIGJ5IG1lXShodHRwczovL2Jpb2Rhc2guZ2l0aHViLmlvL2NvZGVjbHViL3MwMmUwN19nZ3Bsb3QyX3BhcnQyLykKICAKCg==